/*
 * Pipeline.cpp
 *
 *  Created on: May 11, 2012
 *      Author: pleun
 */

#include "Pipeline.h"

Pipeline::Pipeline() {
	commandLines = new vector<Commandline*> ();
	int commandCount = 0;

}

Pipeline::~Pipeline() {
	for (vector<Commandline*>::iterator iter = commandLines->begin(); iter
			!= commandLines->end(); ++iter) {
		delete *iter;
	}
	delete commandLines;
}

void Pipeline::addNewCommandline(Commandline* commandLine) {
	commandLines->push_back(commandLine);
}

void Pipeline::addCommandTextToCommandline(string commandText) {
	commandLines->back()->addNewCommandText(commandText);

}

Commandline* Pipeline::getCommandline() {
	return commandLines->back();
}

void Pipeline::ExecutePipeLine() {

	int fileAppend;
	int fileOutput;
	int fileInput;
	int pid = fork();
	if (pid == 0) {

		Commandline* cmdTmp = commandLines->front();
		char** commandos = convertStringToChar(
				commandLines->back()->getWords(),
				commandLines->back()->getSizeCommandsWithoutFileDirection());
		if (commandLines->size() == 1) {

			//Bij change dir moeten we even wat anders gaan doen dan normaal.
			if (cmdTmp->getWords()->front() == "cd") {
				char * path = commandos[1];
				if (chdir(path) == -1) {
					cout << "chdir failed - \n" << endl;
				} else {
					cout << "changedir to " << path << endl;
				}

			} else {

				if (cmdTmp->GetContainsAppend()) {
					cout << " Append is true " << endl;
					if ((fileAppend = open(cmdTmp->FindPathToAppend().c_str(),
							O_APPEND | O_WRONLY)) < 0) {
						cerr << "Kan niet naar bestand appenden";
						exit(fileAppend);
					}

					dup2(fileAppend, 1);

				}

				if (cmdTmp->GetContainsInput()) {
					cout << " Input is true " << endl;
					if ((fileInput = open(cmdTmp->FindPathToInput().c_str(),
							O_RDONLY)) < 0) {
						cerr << "Kan bestand niet lezen";
						exit(fileInput);
					}
					dup2(fileInput, 0);

				}
				if (cmdTmp->GetContainsOutput()) {
					cout << " Output is true " << endl;
					mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
					if ((fileOutput = open(cmdTmp->FindPathToOutput().c_str(),
							O_TRUNC | O_RDWR | O_CREAT, mode)) < 0) {
						cerr << "Kan niet naar bestand schrijven";
						exit(fileOutput);
					}
					dup2(fileOutput, 1);
				}
				execvp(commandos[0], commandos);
				exit(2);
			}

		} else if (commandLines->size() > 1) {

			commandCount = commandLines->size() - 2;

			if (pid == 0) {
				createPipeLine(commandLines->at(commandLines->size() - 2),
						commandLines->at(commandLines->size() - 1));
			} else {
				wait(&statusProcess);
			}

		} else {
			wait(&statusProcess);
		}

	}
}

char ** Pipeline::convertStringToChar(vector<string>* words, int sizeCommandos) {
	char** argv = new char*[sizeCommandos + 1];
	int counter = 0;

	// waarden even omzetten
	for (vector<string>::const_iterator iter = words->begin(); iter
			!= words->end(); ++iter) {
		if (counter < sizeCommandos) {
			if (*iter == ">" || *iter == "<" || *iter == ">>") {
				cout << "ignore" << endl;
			} else {
				argv[counter] = (char*) ((*words)[counter].c_str());
				counter++;
			}
		} else {
			break;
		}

	}
	// laatste waarde=0 zijn anders accepteert execvp niet
	argv[words->size()] = 0;
	return argv;
}

void Pipeline::createPipeLine(Commandline* cmd1, Commandline* cmd2) {
	int fileAppend;
	int fileOutput;
	int fileInput;
	int filedes[2];

	if (pipe(filedes) == -1) {
		cout << " Pipeline niet aangemaakt" << endl;
	}
	pid_t pid = fork();
	switch (pid) {

	case 0: {
		//cout << "execute 1" << endl;
		dup2(filedes[1], 1);

		close(filedes[0]);
		close(filedes[1]);
		if (cmd1->GetContainsAppend()) {

			if ((fileAppend = open(cmd1->FindPathToAppend().c_str(), O_APPEND
					| O_WRONLY)) < 0) {
				cerr << "Kan niet naar bestand appenden";
				exit(fileAppend);
			}
			dup2(fileAppend, 1);
		}

		if (cmd1->GetContainsInput()) {

			if ((fileInput = open(cmd1->FindPathToInput().c_str(), O_RDONLY))
					< 0) {
				cout << "kan bestand niet lezen";
				exit(fileInput);
			}
			dup2(fileInput, 0);

		}
		if (cmd1->GetContainsOutput()) {
			cout << " Output is true " << endl;
			mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
			if ((fileOutput = open(cmd1->FindPathToOutput().c_str(), O_TRUNC
					| O_RDWR | O_CREAT, mode)) < 0) {
				cout << "Kan niet naar bestand wegschrijven";
				exit(fileOutput);
			}
			dup2(fileOutput, 1);
		}

		//De pipes van acher naar voren laten werken
		commandCount--;
		//cout << "size commandcount" << commandCount << endl;
		if (commandCount >= 0) {
			createPipeLine(commandLines->at(commandCount), cmd1);
		}

		char** com1args = convertStringToChar(cmd1->getWords(),
				cmd1->getSizeCommandsWithoutFileDirection());

		execvp(com1args[0], com1args);
		close(pid);
	}
	default: {

		dup2(filedes[0], 0);
		close(filedes[0]);
		close(filedes[1]);
		if (cmd2->GetContainsAppend()) {
			cout << " Append is true " << endl;
			if ((fileAppend = open(cmd2->FindPathToAppend().c_str(), O_APPEND
					| O_WRONLY)) < 0) {
				cerr << "Kon niet appeenden na de file";
				exit(fileAppend);
			}

			dup2(fileAppend, 1);

		}

		if (cmd2->GetContainsInput()) {
			cout << " Input is true " << endl;
			if ((fileInput = open(cmd2->FindPathToInput().c_str(), O_RDONLY))
					< 0) {
				cerr << "er ging iets mis met input redirectie";
				exit(fileInput);
			}
			dup2(fileInput, 0);

		}
		if (cmd2->GetContainsOutput()) {
			cout << " Output is true " << endl;
			mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
			if ((fileOutput = open(cmd2->FindPathToOutput().c_str(), O_TRUNC
					| O_RDWR | O_CREAT, mode)) < 0) {
				cerr << "er ging iets mis met output redirectie";
				exit(fileOutput);
			}
			dup2(fileOutput, 1);
		}

		char** com2args = convertStringToChar(cmd2->getWords(),
				cmd2->getSizeCommandsWithoutFileDirection());

		execvp(com2args[0], com2args);
		close(pid);

	}
	}

}

